%{
#include <stdio.h>
#include <string.h>
#include <time.h>

#include "parser.h"

#define YYMAXDEPTH 10000000

int zzerror(char *msg);

extern FILE *zzin;

// char *ch;

token_node *bison_tree;

typedef struct node_pair {
	token_node *bison;
	token_node *opp;
} node_pair;

%}

%union {
	token_node *node;
}

%token <node> LBR; 
%token <node> RBR; 
%token <node> LSQ;
%token <node> RSQ;
%left  <node> COM;  
%left  <node> COL;  
%token <node> BOO;   
%token <node> QUO;
%token <node> CHA;   
%token <node> NUM;

%type <node> s
%type <node> obj
%type <node> mem
%type <node> pair
%type <node> val
%type <node> str
%type <node> chars
%type <node> array
%type <node> elem

%%

s: obj {
		fprintf(stdout, "BISON> finished parsing.\n");
		bison_tree = $1;}	
	;

obj: LBR RBR {
		// ch = (char*) malloc(sizeof(char)*5);
		// strcpy(ch, "O:{}");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = OBJECT;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
		}
   | LBR mem RBR {
		// ch = (char*) malloc(sizeof(char)*6);
		// strcpy(ch, "O:{M}");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = OBJECT;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$3->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
        $2->next = $3;
		}
   ;

mem: pair {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "M:P");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = MEMBERS;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
   | mem COM pair {
		// ch = (char*) malloc(sizeof(char)*6);
		// strcpy(ch, "M:M,P");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = MEMBERS;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$3->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
        $2->next = $3;
		}
   ;

pair: str COL val {
		// ch = (char*) malloc(sizeof(char)*6);
		// strcpy(ch, "P:S:V");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = PAIR;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$3->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
        $2->next = $3;
		}
    ;

val: str {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "V:S");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = VALUE;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
   | NUM {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "V:N");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = VALUE;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
   | array {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "V:A");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = VALUE;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
   | obj {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "V:O");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = VALUE;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
   | BOO {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "V:B");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = VALUE;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
   ;

str: QUO QUO {
		// ch = (char*) malloc(sizeof(char)*5);
		// strcpy(ch, "S:\"\"");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = STRING;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
		}
   | QUO chars QUO {
		// ch = (char*) malloc(sizeof(char)*6);
		// strcpy(ch, "S:\"C\"");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = STRING;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$3->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
        $2->next = $3;
		}
   ;

chars: CHA {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "C:c");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = CHARS;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
     | chars CHA {
		// ch = (char*) malloc(sizeof(char)*5);
		// strcpy(ch, "C:Cc");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = CHARS;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
		}
	 ;

array: LSQ RSQ {
		// ch = (char*) malloc(sizeof(char)*5);
		// strcpy(ch, "A:[]");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = ARRAY;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
		}
     | LSQ elem RSQ {
		// ch = (char*) malloc(sizeof(char)*6);
		// strcpy(ch, "A:[E]");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = ARRAY;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$3->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
        $2->next = $3;
		}
	 ;

elem: val {
		// ch = (char*) malloc(sizeof(char)*4);
		// strcpy(ch, "E:V");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = ELEMENTS;
		$$->value = NULL;
		$1->parent = $$;
		$$->next = NULL;
        $$->child = $1;
		}
    | elem COM val {
		// ch = (char*) malloc(sizeof(char)*6);
		// strcpy(ch, "E:E,V");
		$$ = (token_node*) malloc(sizeof(token_node));
		$$->token = ELEMENTS;
		$$->value = NULL;
		$1->parent = $$;
		$2->parent = $$;
		$3->parent = $$;
		$$->next = NULL;
        $$->child = $1;
        $1->next = $2;
        $2->next = $3;
		}
	;

%%

int zzerror(char *msg)
{
	printf("Error: %s\n", msg);
	return 0;
}

int main(int argc, char **argv)
{
	char *file_name = NULL;
	token_node *opp_tree = NULL;
	opp_list *set = NULL, *set_itr = NULL;
	node_pair *pair_alloc = NULL, *pair = NULL;

	/* Get input parameters. */
	file_name = NULL;
	file_name = argv[1];

  fprintf(stdout, "file_name %s\n", file_name);
	
	/* Execute opp. */
	opp_tree = parse(1, file_name);

	/* Execute BISON parser. */
	zzin = fopen(file_name, "r");
	if (zzin == NULL) {
		fprintf(stdout, "ERROR> could not open input file. Aborting.\n");
		return 1;
	}
	if (zzparse() != 0) {
		fprintf(stdout, "ERROR> Bison could not finish parsing.\n");
		fclose(zzin);
		return 1;
	}
	fclose(zzin);

	/* Compare trees. */
	pair_alloc = (node_pair *) malloc(sizeof(node_pair));
	pair_alloc->bison = bison_tree;
	pair_alloc->opp = opp_tree;
	set = opp_list_prepend(set, (void *) pair_alloc);
	while (opp_list_length(set) > 0) {
		pair = (node_pair *) opp_list_get(set, 0);
		/* Remove element from set. */
		set_itr = set;
		set = set->next;
		if (set != NULL) {
			set->prev = NULL;
		}
		free(set_itr);
		/* Compare tokens. */
		if (pair->bison->token != pair->opp->token) {
			fprintf(stdout, "RESULT> trees are different: %p. | %p.\n", pair->bison, pair->opp);
			return 1;
		}
		/* Add sons to set. */
		pair->bison = pair->bison->child;
		pair->opp = pair->opp->child;
		while (pair->bison != NULL && pair->opp != NULL) {
			pair_alloc = (node_pair *) malloc(sizeof(node_pair));
			pair_alloc->bison = pair->bison;
			pair_alloc->opp = pair->opp;
			set = opp_list_prepend(set, (void *) pair_alloc);
			pair->bison = pair->bison->next;
            if (pair->opp->next != NULL && pair->opp->next->parent == pair->opp->parent) {
                pair->opp = pair->opp->next;
            } else {
                pair->opp = NULL;
            }
		}
        if (pair->bison != NULL || pair->opp != NULL) {
			fprintf(stdout, "RESULT> trees are different: different children.\n");
			return 1;
		}
	}
	fprintf(stdout, "RESULT-> trees are identical.\n");

	return 0;
}
